package com.koc.robot;

import android.opengl.GLES11;

import com.koc.robot.common.Vector;


public class Scene {

	private Map mMap;
	private Player mPlayer;
	
	private int mMap2D[][];	//for special perspective
	
	private float mRotation = (float)Math.PI * 0.0f / 180.0f;  	//rotate angle by y-aixs
	private float mPitch = 0.5f;	
	private float mRotationForTick = (float)Math.PI * 0.0f / 180.0f;
	private float mPitchForTick = 0.5f;
	
	private float mBoxWidth = 10.0f;
	private float mBoxWidth_07;
	private float mHalfBoxWidth;
	private float mBoxHeight;
	private float mBoxHeightModded;
	
//	private float mRotateX;
//	private float mRotateY;
	
	private Vector mRelPoints[] = new Vector[4];
	
	private Vector mDrawCenter;
	
	private float mRotateCenterX;
	private float mRotateCenterY;
	private float mRotateCenterZ;
	
	private boolean mIsDrawFace = true;
	private boolean mIsDrawGrid = true;
	
	private float mMapFaceColorFader = 1.0f;
	private float mMapGridColorFader = 1.0f;
	
	private boolean mIsDragRotation = false;
	private float mSmoothRotation = 0;
	private float mSmoothPitch = -1.0f;
	
	public Scene()
	{
		mBoxWidth_07 = mBoxWidth * 0.7f;
		
		for(int i = 0; i < 4; ++i)
		{
			mRelPoints[i] = new Vector(0, 0);
		}
	}
	
	public Map getMap()
	{
		return mMap;
	}
	
	public void setMap(Map map)
	{
		mMap = map;
	}
	
	public void initMap2d()
	{
		int maxX = mMap.getMapWidth() > mMap.getMapDepth() ? mMap.getMapWidth() : mMap.getMapDepth();
		int maxY = mMap.getMapHeight() > mMap.getMapDepth() ? mMap.getMapHeight() : mMap.getMapDepth();
		
		mMap2D = new int[maxX][maxY];
	}
	
	public void setPlayer(Player player)
	{
		mPlayer = player;
	}
	
	public Player getPlayer()
	{
		return mPlayer;
	}
	
	public void setBlockWidth(float width)
	{
		mBoxWidth = width;
		
		mBoxWidth_07 = mBoxWidth * 0.7f;
		mHalfBoxWidth = mBoxWidth * 0.5f;
	}
	
	public float getBlockWidth()
	{
		return mBoxWidth;
	}
	
	public void setDrawCenter(Vector v)
	{
		mDrawCenter = v;
	}
	
	public Vector getDrawCenter()
	{
		return mDrawCenter;
	}
	
	public void setRotateCenter(float rx, float ry, float rz)
	{
		mRotateCenterX = rx;
		mRotateCenterY = ry;
		mRotateCenterZ = rz;
	}
	
	public float getRotation()
	{
		return mRotation;
	}
	
	public void setRotation(float r)
	{
		mRotationForTick = r;
	}
	
	public float getPitch()
	{
		return mPitch;
	}
	
	public void setPitch(float p)
	{
		mPitchForTick = p;
	}
	
	public Vector getRelPoint(int idx)
	{
		if(idx >= 4 || idx < 0)
			return null;
		
		return mRelPoints[idx];
	}
	
	public void setSmoothRotation(float r)
	{
		mSmoothRotation = r;
	}
	
	public void setSmoothPitch(float s)
	{
		mSmoothPitch = s;
	}
	
	public void setRotateDrag(boolean b)
	{
		mIsDragRotation = b;
	}
	
	
	public boolean isDrawFace()
	{
		return mIsDrawFace;
	}
	
	public boolean isDrawGrid()
	{
		return mIsDrawGrid;
	}
	
	public float getMapFaceColorFader()
	{
		return mMapFaceColorFader;
	}
	
	public float getMapGridColorFader()
	{
		return mMapGridColorFader;
	}
	
	public float getBoxHeightModded()
	{
		return mBoxHeightModded;
	}
	
	public int[][] getMap2D()
	{
		return mMap2D;
	}
	
	public Vector convertGRDToSCR(float x, float y, float z)
	{
		Vector ret = new Vector(0, 0);
		
		float angle = (float)Math.atan2(x - mRotateCenterX, z - mRotateCenterZ);
		float r = (float)Math.sqrt(Math.pow(x - mRotateCenterX, 2) + Math.pow(z - mRotateCenterZ, 2)); 
		
		ret.x = mDrawCenter.x + (float)Math.cos(angle + mRotation + Common.PI_025) * r * mBoxWidth_07;
		ret.y = mDrawCenter.y + (float)Math.sin(angle + mRotation + Common.PI_025) * r * mBoxWidth_07 * mPitch + 
				(mRotateCenterY - y) * mBoxHeightModded;		
		
		return ret;
	}
	
	void calculate()
	{
		mBoxHeight = mBoxWidth * 0.9f;
		mHalfBoxWidth = mBoxWidth / 2;
		mBoxHeight = mBoxHeight * (float)Math.sin(Common.PI_025);
		mBoxWidth_07 = mBoxWidth * 0.7f;
		float boxHeightMod = 1 - (float)Math.pow(mPitch, 3);
		mBoxHeightModded = mBoxHeight * boxHeightMod;
		
		mRelPoints[0].x = (float)Math.cos(mRotation) * mHalfBoxWidth;
		mRelPoints[0].y = (float)Math.sin(mRotation) * mHalfBoxWidth * mPitch;
		mRelPoints[1].x = (float)Math.cos(mRotation + Common.PI_05) * mHalfBoxWidth;
		mRelPoints[1].y = (float)Math.sin(mRotation + Common.PI_05) * mHalfBoxWidth * mPitch;
		mRelPoints[2].x = (float)Math.cos(mRotation + Common.PI) * mHalfBoxWidth;
		mRelPoints[2].y = (float)Math.sin(mRotation + Common.PI) * mHalfBoxWidth * mPitch;
		mRelPoints[3].x = (float)Math.cos(mRotation + Common.PI_15) * mHalfBoxWidth;
		mRelPoints[3].y = (float)Math.sin(mRotation + Common.PI_15) * mHalfBoxWidth * mPitch;		
	}	
	
	public void update(float dt)
	{
	//	calculate();
		smoothRotation(dt);
		
		if(mMap2D != null)
		{
			updateMap2D();
		}
	}
	
	public void render()
	{
		GLES11.glEnable(GLES11.GL_DEPTH_TEST);
		GLES11.glClearDepthf(0.0f);
		GLES11.glDepthFunc(GLES11.GL_GEQUAL );
		calculate();
		mMap.render();
		GLES11.glDisable(GLES11.GL_DEPTH_TEST);
		
		mRotation = mRotationForTick;		
		mPitch = mPitchForTick;
	}
	
	public void smoothRotation(float delta)
	{
		if(mIsDragRotation == false)
		{
			if(mSmoothRotation != 0)
			{
				float test1 = mSmoothRotation - mRotationForTick;
				mRotationForTick = smooth(mRotationForTick, mSmoothRotation, delta);
				float test2 = mSmoothRotation - mRotationForTick;
				if(test1 * test2 <= 0.0f)
				{
					mSmoothRotation = 0;
				}
			}
			
			if(mSmoothPitch >= 0.0f)
			{
				float test1 = mSmoothPitch - mPitchForTick;
				mPitchForTick = smooth(mPitchForTick , mSmoothPitch, delta);
				float test2 = mSmoothPitch - mPitchForTick;
				if(test1 * test2 <= 0.0f)
				{
					mSmoothPitch = -1.0f;
				}
			}
		}
	}
	
	public float smooth(float start, float target, float dt)
	{
		float ret = start;
		if(start < target)
		{
			ret = start + 3 * dt + (target - start) / 3.0f * dt * 20;
			if(ret > target)
				ret = target;
		}
		else if(start > target)
		{
			ret = start - 3 * dt - (start - target) / 3.0f * dt * 20;
			if(ret < target)
				ret = target;
		}
		
		return ret;
	}
	
	public void updateMap2D()
	{
		mMap.updateMap2D(mMap2D);
	}
}
